#include "catalog.h"
#include <cstdlib>



RelCatalog::RelCatalog(Status &status) :
	 HeapFile(RELCATNAME, status)
{
// nothing should be needed here
}

// return the relation description matching the relation name queried
// return OK if it's well done otherwise return the error code
const Status RelCatalog::getInfo(const string & relation, RelDesc &record)
{
  if (relation.empty())
    return BADCATPARM;

  Status status;
  Record rec;
  RID rid;

  // scan the relation catalog
  HeapFileScan *hfs =  new HeapFileScan(RELCATNAME, status);
  // start scan
  status = hfs->startScan(0, relation.length() + 1, STRING, relation.c_str(),EQ);
  if (status != OK)
  {
    delete hfs;
    return status;
  }
  // scan next
  status = hfs->scanNext(rid);
  // if it's end of file, it infers nothing found
  if (status == FILEEOF) 
  {
    delete hfs;
    status = RELNOTFOUND;
    return status;
  }else if (status != OK){
    delete hfs;
    return status;
  }
  // get relation description pointer
  status = hfs->getRecord(rec);
  if (status != OK) 
  {
    delete hfs;
    return status;
  }
  // copy the relation info data
  if (rec.length == sizeof(RelDesc))
  {
    memcpy(&record, rec.data, rec.length);
  }

  delete hfs;
  return status;
  
}

// add relation description into relation catalog contained in record param
// return OK if it's well done, otherwise return error codes
const Status RelCatalog::addInfo(RelDesc & record)
{
  RID rid;
  InsertFileScan*  ifs;
  Status status;

  ifs = new InsertFileScan(RELCATNAME, status);
  // specify the location of the relation info stored
  Record rec;
  rec.length = sizeof(RelDesc);
  rec.data = (void*) &record;
  // insert record into catalog
  status = ifs->insertRecord(rec, rid);
  
  delete ifs;
  return status;

}

// remove the relation info from relation catalog 
// return OK if it's well done, otherwise return error codes
const Status RelCatalog::removeInfo(const string & relation)
{
  Status status;
  RID rid; 
  HeapFileScan*  hfs;

  if (relation.empty()) return BADCATPARM;
  // find the info in the relation catalog
  hfs = new HeapFileScan(RELCATNAME, status);
  
  // start scan
  status = hfs->startScan(0, relation.length() + 1, STRING,    relation.c_str(),EQ);
  if (status != OK)
  {
    delete hfs;
    return status;
  } 
  // scan next
  status = hfs->scanNext(rid);
  if (status == FILEEOF) 
  {
    delete hfs;
    status = RELNOTFOUND;
    return status;
  }else if (status != OK)
  {
    delete hfs;
    return status;
  }
  // delete the relation info in relation catalog
  status = hfs->deleteRecord();
  // release the scan object
  delete hfs;
  return status;

  
}



RelCatalog::~RelCatalog()
{
// nothing should be needed here
}


AttrCatalog::AttrCatalog(Status &status) :
	 HeapFile(ATTRCATNAME, status)
{
// nothing should be needed here
}


// get the attribute info quried by the relation name and attrName
// return the AttrDesc in record and OK if it's well done 
// return error codes if there are any
const Status AttrCatalog::getInfo(const string & relation, 
				  const string & attrName,
				  AttrDesc &record)
{

  Status status;
  RID rid;
  Record rec;
  HeapFileScan*  hfs;

  if (relation.empty() || attrName.empty()) return BADCATPARM;
  
  hfs =  new HeapFileScan(ATTRCATNAME, status);
  // start scan
  status = hfs->startScan(MAXNAME, MAXNAME, STRING, attrName.c_str(),EQ);
  if (status != OK)
  {
    delete hfs;
    return status;
  }
  // scan next
  status = hfs->scanNext(rid);
 
  while (status != FILEEOF)
  {
    if (status != OK){
      delete hfs;
      return status;
    }

    // get record
    status = hfs->getRecord(rec);
    if (status != OK) 
    {
      delete hfs;
      return status;
    }
    // copy record data
    if ((strcmp(relation.c_str(), (char *)rec.data) == 0) )
    {
      memcpy(&record, rec.data, rec.length);
      delete hfs;
      return status;
    }
  }
  
  delete hfs;
  // if it's end of file, it infers nothing is found.
  return ATTRNOTFOUND;
}

// add the attribute info given by record into the attribute catalog 
// return OK if it's well done otherwise return the error codes.
const Status AttrCatalog::addInfo(AttrDesc & record)
{
  RID rid;
  InsertFileScan*  ifs;
  Status status;

  ifs = new InsertFileScan (ATTRCATNAME, status);
  if(status != OK) 
  {
      delete ifs;
      return status;
  }
  // put the attribute info into a temprary record
  Record rec;
  rec.data = (void*) &record;
  rec.length = sizeof (record);
  // insert the info
  status = ifs->insertRecord(rec, rid);
  delete ifs;
  return status;


}


// remove the attribute info from attribute catalog 
// return OK if it's well done, otherwise return error codes
const Status AttrCatalog::removeInfo(const string & relation, 
			       const string & attrName)
{
  Status status;
  Record rec;
  RID rid;
  // AttrDesc record;
  HeapFileScan*  hfs;

  if (relation.empty() || attrName.empty()) return BADCATPARM;
  
  hfs = new HeapFileScan(ATTRCATNAME, status);
  status = hfs->startScan(MAXNAME, MAXNAME, STRING, attrName.c_str(),EQ);
  if (status != OK)
  {
    delete hfs;
    return status;
  }
  // scan next
  status = hfs->scanNext(rid);
 
  while (status != FILEEOF)
  {
    if (status != OK)
    {
      delete hfs;
      return status;
    }

    // get attr info
    status = hfs->getRecord(rec);
    if (status != OK) 
    {
      delete hfs;
      return status;
    }
    // delete record data
    if ((strcmp(relation.c_str(), (char *)rec.data) == 0) )
    {
      status = hfs->deleteRecord();
      delete hfs;
      return status;
    }
    status = hfs->scanNext(rid);
  }
  delete hfs;
  // if it's end of file, it infers the attrdesc not found
  return ATTRNOTFOUND;

}


// return all the attrbutes and attrCnt info in a relation
// return OK if nothing is wrong, otherwise return the error codes 
const Status AttrCatalog::getRelInfo(const string & relation, 
				     int &attrCnt,
				     AttrDesc *&attrs)
{
  Status status;
  RID rid;
  Record rec;
  HeapFileScan*  hfs;

  if (relation.empty()) return BADCATPARM;
  

  attrCnt = 0;
  //initialize a scan to find the relation in catalog
  hfs = new HeapFileScan(ATTRCATNAME, status);
  status = hfs->startScan(0, MAXNAME, STRING, relation.c_str(),EQ);
  if (status != OK)
  {
    delete hfs;
    return status;
  }

  status = hfs->scanNext(rid);
  while(status != FILEEOF){
    if (status != OK){
      delete hfs;
      return status;
    }
    if (attrCnt == 0)
    {
      attrs = (AttrDesc*)malloc(sizeof(AttrDesc));
    }else
    {
      attrs = (AttrDesc*)realloc(attrs, sizeof(AttrDesc)*(attrCnt + 1));
    }
  	status = hfs->getRecord(rec);
        if (status != OK) 
        {
          delete hfs;
          return status;
        }

      //copy the attr info to the list attrs
      if ((strcmp(relation.c_str(), (char *)rec.data) == 0) )
      {
        memcpy(&attrs[attrCnt], rec.data, rec.length);
      }
      status = hfs->scanNext(rid);
      // count the number attr processed.
      attrCnt++;
      
  }

  // if no attr is found, it infers the rel is not found
  if ( attrCnt == 0) return  RELNOTFOUND; 
  delete hfs;
  return OK;
}





AttrCatalog::~AttrCatalog()
{
// nothing should be needed here
}

